#include "Widget.h"
#include "Widgets/WidgetTree.h"

#include "Window.h"
#include "Render/Widget/RenderSurface.h"
#include "Render/Widget/RenderWidgets.h"
#include "Render/RenderContext.h"

static bool bDrawDebugBox=true;

RWidget::RWidget()
{
    Tags=std::make_unique<CTags>();
}

TSharedObjectPtr<RWidget> RWidget::FindSubWidgetByName(const CString & InName)
{
    for(auto& SubWidget: SubWidgets)
    {
        if(SubWidget->Name.Get()==InName)
        {
            return SubWidget;
        }
    }
    return nullptr;
}

void RWidget::Paint(uint16_t& InZOrder)
{
    RenderState=ERenderState::Normal;
    if(!Visible.Get())
    {
        RenderState=ERenderState::Invisible;
        RecursivelySetSubwidgetRenderState(ERenderState::ParentInvisible);
        return;
    }

    auto PaintArea=GetPaintArea();
    bool IsClippedOut=PresentSize.X<=0 || PresentSize.Y<=0 || !PaintArea.HasValue();
    if(IsClippedOut)
    {
        RenderState=ERenderState::ClippedOut;
    }
    else
    {
        PaintSelf(InZOrder,PaintArea.GetValue());

        if(IsPaintDebugBoxEnabled())
        {
            PaintSelfDebugBox();
        }
    }
    
    PaintSubWidgets(InZOrder);

}

void RWidget::PaintSelf(uint16_t& InZOrder,const SRect& InClipArea)
{
    return;
}

bool RWidget::IsPaintDebugBoxEnabled()
{
    return bDrawDebugBox;
}

void RWidget::EnablePaintDebugBox()
{
    bDrawDebugBox=true;
}

void RWidget::DisablePaintDebugBox()
{
    bDrawDebugBox=false;
}

void RWidget::PaintSelfDebugBox()
{
    return;
}

void RWidget::PaintSubWidgets(uint16_t& InZOrder)
{
    for(auto& SubWidget: SubWidgets)
    {
        SubWidget->Paint(InZOrder);
    }
}

void RWidget::AddSubWidget(RWidgetPtr  InWidget)
{
    assert(InWidget);
    if(InWidget->Parent)
    {   
        assert(InWidget->Parent !=this && "cant add a subwidget twice");
        InWidget->RemoveFromParent();
    }
    InWidget->Parent=this;
    SubWidgets.Add(InWidget);

    InWidget->SetOwner(this);
    InWidget->Register(GetWidgetTree());

}

void RWidget::RemoveSubWidget(RWidgetPtr InSubWidget)
{
    assert(InSubWidget && "trying remove a invalid subwidget");

    SubWidgets.Remove(InSubWidget);

    InSubWidget->SetOwner(WH::GetTransientAsset());
    InSubWidget->Unregister();
    InSubWidget->Parent=nullptr;
}

void RWidget::RemoveSubWidgetAt(int64_t Index)
{
    RemoveSubWidget(SubWidgets[Index]);
}

void RWidget::RemoveFromParent()
{
    assert(Parent && "do not have parent widget");
    Parent->RemoveSubWidget(this);
}

void RWidget::SetParent(RWidget *InParentWidget)
{
    //check current parent is not this
    if(Parent==InParentWidget)
    {
        return;
    }

    //remove from current parent
    if(Parent)
    {
        Parent->RemoveSubWidget(this);
    }

    //add to new parent
    if(InParentWidget)
    {
        InParentWidget->AddSubWidget(this);
    }
    else
    {
        Parent=nullptr;
    }
}

TVector<RWidgetPtr> RWidget::GetSubWidgets()
{
    return SubWidgets;
}

RWidgetPtr RWidget::GetSubWidget(int64_t Index)
{
    return SubWidgets[Index];
}

bool RWidget::HasAnySubWidget()
{
    return !SubWidgets.Empty();
}

void RWidget::InsertSubWidget(int64_t Index,RWidgetPtr InWidget)
{
    assert(InWidget);
    assert(Index>=0);
    
    if(InWidget->Parent)
    {
        assert(InWidget->Parent !=this && "cant add a subwidget twice");
        InWidget->RemoveFromParent();
    }
    InWidget->Parent=this;
    SubWidgets.Insert(Index, InWidget);
    InWidget->SetOwner(this);
    InWidget->Register(GetWidgetTree());

}

void RWidget::MoveSubWidget(int64_t FromIndex, int64_t ToIndex)
{
    assert(FromIndex>=0 && FromIndex<SubWidgets.Num());
    assert(ToIndex>=0 && ToIndex<SubWidgets.Num());

    SubWidgets.Move(FromIndex,ToIndex);
}

bool RWidget::IsDescendantsOf(RWidgetPtr InParentWidget)
{
    if(!Parent)
    {
        return false;
    }

    if(Parent==InParentWidget.Get())
    {
        return true;
    }

    return Parent->IsDescendantsOf(InParentWidget);

}

void RWidget::PaintRenderWidget(std::shared_ptr<SRenderWidgetBase> InRenderWidget)
{
    GetWindow()
        ->RenderSurface
        ->Widgets[RRenderContext::Get()->CurrentWriteBufferIndex]
        .Add(InRenderWidget);  
}

void RWidget::ClearSubWidgets()
{
    for(auto& SubWidget:SubWidgets )
    {
        SubWidget->Parent=nullptr;
        SubWidget->SetOwner(WH::GetTransientAsset());
        SubWidget->Unregister();
    }
    SubWidgets.Clear();
}

void RWidget::DestroySubWidgets()
{
    auto SubWidgetsCopy=SubWidgets;
    ClearSubWidgets();
    
    TVector<RObject* > SubWidgetsCopyAsObject;
    for(auto& SubWidget:SubWidgetsCopy)
    {
        SubWidgetsCopyAsObject.Add(SubWidget.Get());
    }
    WH::DestroyObjects(SubWidgetsCopyAsObject);
}

int64_t RWidget::GetSubWidgetNum()
{
    return SubWidgets.Num();
}

CWidgetTree * RWidget::GetWidgetTree() const
{
    return Tree;
}

bool  RWidget::IsRegistered() 
{
    return Tree!=nullptr;
}


void RWidget::Register(CWidgetTree * InTree)
{
    assert(!IsRegistered());
    if(!InTree)
    {
        //cant register to a null tree
        return;
    }

    Tree=InTree;

    for(auto& Child:SubWidgets)
    {
        Child->Register(InTree);
    }
}

void RWidget::Unregister()
{
    if(!IsRegistered())
    {
        return;
    }

    Tree=nullptr;

    for(auto& Child:SubWidgets)
    {
        Child->Unregister();
    }
}

void RWidget::CalculateChildrenPresentPositionAndSize()
{
    for(auto& Child:SubWidgets)
    {
        Child->CalculatePresentPositionAndSize();
    }
}

SVec2 RWidget::GetAccumulatedScale()
{
    if(!Parent)
    {
        return Scale.Get();
    }

    return Parent->GetAccumulatedScale() *Scale.Get();
}

TTuple<float,float> RWidget::CalculateXAndWidth()
{

    float ResultX;
    float ResultWidth;
   

    //calculate Horizontal position and size
    RWidget* LeftWidget=Anchor.LeftReference.IsValid()? Anchor.LeftReference.Get().Get() : nullptr;
    RWidget* RightWidget=Anchor.RightReference.IsValid()? Anchor.RightReference.Get().Get(): nullptr;
    RWidget* HCenterWidget=Anchor.HorizontalCenterReference.IsValid()? Anchor.HorizontalCenterReference.Get().Get(): nullptr;
    
    float _XScale=Parent->GetAccumulatedScale().X;
    //six situation
    if(LeftWidget)
    {
        float _LeftOffset=Anchor.LeftOffset.Get()*_XScale;
        switch(Anchor.LeftReferenceEdge.Get())
        {
            case EHorizontalWidgetEdge::Left:
            ResultX=LeftWidget->GetPresentAbsolutePosition().X+ _LeftOffset;  
            break;
            case EHorizontalWidgetEdge::Right:
            ResultX=LeftWidget->GetPresentAbsolutePosition().X+LeftWidget->GetPresentSize().X +  _LeftOffset;  
            break;           
            case EHorizontalWidgetEdge::Center:
            ResultX=LeftWidget->GetPresentAbsolutePosition().X+LeftWidget->GetPresentSize().X/2 + _LeftOffset;  
            break;            
        }

        if(HCenterWidget)
        {
            float Center;
            
            float _HorizontalCenterOffset=Anchor.HorizontalCenterOffset.Get()*_XScale;
            switch(Anchor.HorizontalCenterReferenceEdge.Get())
            {
                case EHorizontalWidgetEdge::Left:
                Center=HCenterWidget->GetPresentAbsolutePosition().X + _HorizontalCenterOffset;
                break;
                case EHorizontalWidgetEdge::Right:
                Center=HCenterWidget->GetPresentAbsolutePosition().X+ HCenterWidget->GetPresentSize().X + _HorizontalCenterOffset; 
                break;           
                case EHorizontalWidgetEdge::Center:
                Center=HCenterWidget->GetPresentAbsolutePosition().X+ HCenterWidget->GetPresentSize().X/2 +  _HorizontalCenterOffset;
                break;                   
            }
            
            ResultWidth=  (Center- ResultX) *2;

            //ignore Right widget because two anchor reference is enough

        }
        else if(RightWidget)
        {
            float Right;
            
            float _RightOffset=Anchor.RightOffset.Get()*_XScale;
            switch(Anchor.RightReferenceEdge.Get())
            {
                case EHorizontalWidgetEdge::Left:
                Right=RightWidget->GetPresentAbsolutePosition().X-  _RightOffset  ;
                break;
                case EHorizontalWidgetEdge::Right:
                Right=RightWidget->GetPresentAbsolutePosition().X+ RightWidget->GetPresentSize().X-  _RightOffset  ;
                break;           
                case EHorizontalWidgetEdge::Center:
                Right=RightWidget->GetPresentAbsolutePosition().X+ RightWidget->GetPresentSize().X /2- _RightOffset ;
                break; 
            };

            ResultWidth=Right-ResultX;
        }
        else
        {
            //only have left constraint
            if(Width.IsValid())
            {
                ResultWidth=_XScale *Width.Get();
            }
            else
            {
                ResultWidth=_XScale *CalculateContentWidth();
            }
        }
    }
    else if(RightWidget)
    {
        float Right;
        
        float _RightOffset=Anchor.RightOffset.Get()*_XScale;
        switch(Anchor.RightReferenceEdge.Get())
        {
            case EHorizontalWidgetEdge::Left:
            Right=RightWidget->GetPresentAbsolutePosition().X-  _RightOffset  ;
            break;
            case EHorizontalWidgetEdge::Right:
            Right=RightWidget->GetPresentAbsolutePosition().X+ RightWidget->GetPresentSize().X- _RightOffset  ;
            break;           
            case EHorizontalWidgetEdge::Center:
            Right=RightWidget->GetPresentAbsolutePosition().X+ RightWidget->GetPresentSize().X /2-  _RightOffset ;
            break; 
        };

        if(HCenterWidget)
        {
            float Center;
            
            float _HorizontalCenterOffset=Anchor.HorizontalCenterOffset.Get()*_XScale;
            switch(Anchor.HorizontalCenterReferenceEdge.Get())
            {
                case EHorizontalWidgetEdge::Left:
                Center=HCenterWidget->GetPresentAbsolutePosition().X + _HorizontalCenterOffset;
                break;
                case EHorizontalWidgetEdge::Right:
                Center=HCenterWidget->GetPresentAbsolutePosition().X+ HCenterWidget->GetPresentSize().X + _HorizontalCenterOffset; 
                break;           
                case EHorizontalWidgetEdge::Center:
                Center=HCenterWidget->GetPresentAbsolutePosition().X+ HCenterWidget->GetPresentSize().X/2 + _HorizontalCenterOffset;
                break;                   
            }

            ResultWidth=  (Right-Center) *2;
            ResultX= Right - ResultWidth;
        }
        else
        {
            
            if(Width.IsValid())
            {
                //both width and right constraint
                ResultWidth=_XScale* Width.Get();
                ResultX= Right -  ResultWidth;
            }
            else if(X.IsValid())
            {
                //both X and right constraint
                ResultX= X.Get()*_XScale +Parent->GetPresentAbsolutePosition().X;
                ResultWidth=Right-ResultX;
            }
            else
            {
                // only have right constraint
                ResultWidth=_XScale*CalculateContentWidth();
                ResultX= Right -  ResultWidth;
            }
        }

    }
    else if(HCenterWidget)
    {
        // only have center constraint
        float Center;
            
        float _HorizontalCenterOffset=Anchor.HorizontalCenterOffset.Get()*_XScale;
        switch(Anchor.HorizontalCenterReferenceEdge.Get())
        {
            case EHorizontalWidgetEdge::Left:
            Center=HCenterWidget->GetPresentAbsolutePosition().X +_HorizontalCenterOffset;
            break;
            case EHorizontalWidgetEdge::Right:
            Center=HCenterWidget->GetPresentAbsolutePosition().X+ HCenterWidget->GetPresentSize().X + _HorizontalCenterOffset; 
            break;           
            case EHorizontalWidgetEdge::Center:
            Center=HCenterWidget->GetPresentAbsolutePosition().X+ HCenterWidget->GetPresentSize().X/2 + _HorizontalCenterOffset;
            break;                   
        }

        if(Width.IsValid())
        {
            //both width and center constraint
            ResultWidth=_XScale* Width.Get();
            ResultX=  Center-   ResultWidth/2;
        }
        else if(X.IsValid())
        {
            //both X and center constraint
            ResultX= X.Get()*_XScale  +Parent->GetPresentAbsolutePosition().X;
            ResultWidth=  (Center- ResultX) *2;
        }
        else
        {
            //only have center constraint
            ResultWidth=_XScale*CalculateContentWidth();
            ResultX=  Center-   ResultWidth/2;
        }
    }    
    else
    {
        //no anchor
        if(Width.IsValid())
        {
            ResultWidth=_XScale* Width.Get();
        }
        else
        {
            ResultWidth=_XScale* CalculateContentWidth();
        }
        ResultX=Parent->PresentAbsPosition.X+ _XScale* X.Get();
    }

    return WH::MakeTuple(ResultX,ResultWidth);
}

TTuple<float,float> RWidget::CalculateYAndHeight()
{
    float ResultY;
    float ResultHeight;

    //calculate Vertical position and size
    RWidget* TopWidget=Anchor.TopReference.IsValid()? Anchor.TopReference.Get().Get() : nullptr;
    RWidget* BottomWidget=Anchor.BottomReference.IsValid()? Anchor.BottomReference.Get().Get(): nullptr;
    RWidget* VCenterWidget=Anchor.VerticalCenterReference.IsValid()? Anchor.VerticalCenterReference.Get().Get(): nullptr;

    float _YScale=Parent->GetAccumulatedScale().Y;

    //six situation
    if(TopWidget)
    {
        float _TopOffset=Anchor.TopOffset.Get()*_YScale;
        switch(Anchor.TopReferenceEdge.Get())
        {
            case EVerticalWidgetEdge::Top:
            ResultY=TopWidget->GetPresentAbsolutePosition().Y+ _TopOffset;  
            break;
            case EVerticalWidgetEdge::Bottom:
            ResultY=TopWidget->GetPresentAbsolutePosition().Y+TopWidget->GetPresentSize().Y +_TopOffset;  
            break;           
            case EVerticalWidgetEdge::Center:
            ResultY=TopWidget->GetPresentAbsolutePosition().Y+TopWidget->GetPresentSize().Y/2 + _TopOffset;  
            break;            
        }

        if(VCenterWidget)
        {
            float Center;
            
            float _VerticalCenterOffset=Anchor.VerticalCenterOffset.Get()*_YScale;
            switch(Anchor.VerticalCenterReferenceEdge.Get())
            {
                case EVerticalWidgetEdge::Top:
                Center=VCenterWidget->GetPresentAbsolutePosition().Y + _VerticalCenterOffset;
                break;
                case EVerticalWidgetEdge::Bottom:
                Center=VCenterWidget->GetPresentAbsolutePosition().Y+ VCenterWidget->GetPresentSize().Y +_VerticalCenterOffset; 
                break;           
                case EVerticalWidgetEdge::Center:
                Center=VCenterWidget->GetPresentAbsolutePosition().Y+ VCenterWidget->GetPresentSize().Y/2 + _VerticalCenterOffset;
                break;                   
            }
            ResultHeight=  (Center- ResultY) *2;

        }
        else if(BottomWidget)
        {

            float Bottom;
            
            float _BottomOffset=Anchor.BottomOffset.Get()*_YScale;
            switch(Anchor.BottomReferenceEdge.Get())
            {
                case EVerticalWidgetEdge::Top:
                Bottom=BottomWidget->GetPresentAbsolutePosition().Y-  _BottomOffset ;
                break;
                case EVerticalWidgetEdge::Bottom:
                Bottom=BottomWidget->GetPresentAbsolutePosition().Y+ BottomWidget->GetPresentSize().Y-  _BottomOffset ;
                break;           
                case EVerticalWidgetEdge::Center:
                Bottom=BottomWidget->GetPresentAbsolutePosition().Y+ BottomWidget->GetPresentSize().Y /2-  _BottomOffset;
                break; 
            };

            ResultHeight=Bottom-ResultY;

        }else
        {
            //only have top constraint
            if(Height.IsValid())
            {
                ResultHeight=_YScale* Height.Get();
            }
            else
            {
                ResultHeight=_YScale*CalculateContentHeight();
            }

        }
    }
    else if(BottomWidget)
    {
        float Bottom;
            
        float _BottomOffset=Anchor.BottomOffset.Get()*_YScale;
        switch(Anchor.BottomReferenceEdge.Get())
        {
            case EVerticalWidgetEdge::Top:
            Bottom=BottomWidget->GetPresentAbsolutePosition().Y-  _BottomOffset  ;
            break;
            case EVerticalWidgetEdge::Bottom:
            Bottom=BottomWidget->GetPresentAbsolutePosition().Y+ BottomWidget->GetPresentSize().Y-  _BottomOffset  ;
            break;           
            case EVerticalWidgetEdge::Center:
            Bottom=BottomWidget->GetPresentAbsolutePosition().Y+ BottomWidget->GetPresentSize().Y /2-  _BottomOffset ;
            break; 
        };

        if(VCenterWidget)
        {
            float Center;
            
            float _VerticalCenterOffset=Anchor.VerticalCenterOffset.Get()*_YScale;
            switch(Anchor.VerticalCenterReferenceEdge.Get())
            {
                case EVerticalWidgetEdge::Top:
                Center=VCenterWidget->GetPresentAbsolutePosition().Y + _VerticalCenterOffset;
                break;
                case EVerticalWidgetEdge::Bottom:
                Center=VCenterWidget->GetPresentAbsolutePosition().Y+ VCenterWidget->GetPresentSize().Y + _VerticalCenterOffset; 
                break;           
                case EVerticalWidgetEdge::Center:
                Center=VCenterWidget->GetPresentAbsolutePosition().Y+ VCenterWidget->GetPresentSize().Y/2 + _VerticalCenterOffset;
                break;                   
            }

            ResultHeight=  (Bottom-Center) *2;
            ResultY= Bottom - ResultHeight;
        }
        else
        {
            if(Height.IsValid())
            {
                //both height and bottom constraint
                ResultHeight=_YScale* Height.Get();
                ResultY= Bottom -  ResultHeight;
            }
            else if(Y.IsValid())
            {
                //both Y and bottom constraint
                ResultY= Y.Get()* _YScale  +Parent->GetPresentAbsolutePosition().Y;
                ResultHeight=Bottom-ResultY;
            }
            else
            {
                // only have bottom constraint
                ResultHeight=_YScale*CalculateContentHeight();
                ResultY= Bottom - ResultHeight;
            }
        }

    }
    else if(VCenterWidget)
    {
        // only have center constraint
        float Center;
            
        float _VerticalCenterOffset=Anchor.VerticalCenterOffset.Get()*_YScale;
        switch(Anchor.VerticalCenterReferenceEdge.Get())
        {
            case EVerticalWidgetEdge::Top:
            Center=VCenterWidget->GetPresentAbsolutePosition().Y + _VerticalCenterOffset;
            break;
            case EVerticalWidgetEdge::Bottom:
            Center=VCenterWidget->GetPresentAbsolutePosition().Y+ VCenterWidget->GetPresentSize().Y + _VerticalCenterOffset; 
            break;           
            case EVerticalWidgetEdge::Center:
            Center=VCenterWidget->GetPresentAbsolutePosition().Y+ VCenterWidget->GetPresentSize().Y/2 + _VerticalCenterOffset;
            break;                   
        }

        if(Height.IsValid())
        {
            //both height and center constraint
            ResultHeight=_YScale* Height.Get();
            ResultY=  Center-   ResultHeight/2;
        }
        else if(Y.IsValid())
        {
            //both Y and center constraint
            ResultY= Y.Get()*_YScale +Parent->GetPresentAbsolutePosition().Y;
            ResultHeight=  (Center- ResultY) *2;
        }
        else
        {
            //only have center constraint
            ResultHeight=_YScale*CalculateContentHeight();
            ResultY=  Center-   ResultHeight/2;
        }
    }
    else
    {
        //no anchor
        if(Height.IsValid())
        {
            ResultHeight=_YScale* Height.Get();
        }
        else
        {
            ResultHeight=_YScale*CalculateContentHeight();
        }
        ResultY=Parent->GetPresentAbsolutePosition().Y+ _YScale* Y.Get();
    }

    return WH::MakeTuple(ResultY,ResultHeight);

}

void RWidget::Tick(float DeltaSeconds)
{
    for(auto& SubWidget:SubWidgets)
    {
        SubWidget->Tick(DeltaSeconds);
    }
}

void RWidget::CalculateSelfPresentPositionAndSize()
{
    //calculate position and size
    //do not apply self scale, use parent scale
    auto XAndWidth=CalculateXAndWidth();
    PresentAbsPosition.X=XAndWidth.First;
    PresentSize.X=XAndWidth.Second;

    auto YAndHeight=CalculateYAndHeight();
    PresentAbsPosition.Y=YAndHeight.First;
    PresentSize.Y=YAndHeight.Second;

    //apply self sacle
    SVec2 _Scale=  Scale.Get();
    switch(Origin.Get())
    {
        case EWidgetOriginType::LeftTop:
        {
            PresentSize=PresentSize*_Scale;
            break;
        }

        case EWidgetOriginType::LeftCenter:
        {
            float CenterY=PresentSize.Y*0.5+PresentAbsPosition.Y;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition.Y=CenterY-PresentSize.Y*0.5;
            break;
        }

        case EWidgetOriginType::LeftBottom:
        {
            float BottomY=PresentSize.Y+PresentAbsPosition.Y;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition.Y=BottomY-PresentSize.Y;
            break;
        }

        case EWidgetOriginType::RightTop:
        {
            float RightX=PresentSize.X+PresentAbsPosition.X;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition.X=RightX-PresentSize.X;
            break;
        }

        case EWidgetOriginType::RightCenter:
        {
            float RightX=PresentSize.X+PresentAbsPosition.X;
            float CenterY=PresentSize.Y*0.5+PresentAbsPosition.Y;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition.X=RightX-PresentSize.X;
            PresentAbsPosition.Y=CenterY-PresentSize.Y*0.5;
            break;
        }

        case EWidgetOriginType::RightBottom:
        {
            float RightX=PresentSize.X+PresentAbsPosition.X;
            float BottomY=PresentSize.Y+PresentAbsPosition.Y;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition.X=RightX-PresentSize.X;
            PresentAbsPosition.Y=BottomY-PresentSize.Y;
            break;
        }

        case EWidgetOriginType::TopCenter:
        {
            float CenterX=PresentSize.X*0.5+PresentAbsPosition.X;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition.X=CenterX-PresentSize.X*0.5;
            break;
        }

        case EWidgetOriginType::BottomCenter:
        {
            float CenterX=PresentSize.X*0.5+PresentAbsPosition.X;
            float BottomY=PresentSize.Y+PresentAbsPosition.Y;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition.X=CenterX-PresentSize.X*0.5;
            PresentAbsPosition.Y=BottomY-PresentSize.Y;
            break;
        }

        case EWidgetOriginType::Center:
        {
            SVec2 Center=PresentSize*0.5+PresentAbsPosition;
            PresentSize=PresentSize*_Scale;
            PresentAbsPosition=Center-PresentSize*0.5;
            break;
        }


        //TODO address Add more origin
        default:
            assert(false&& "Unimplemnt");
    }
}

void RWidget::CalculatePresentPositionAndSize()
{
    CalculateSelfPresentPositionAndSize();
    CalculateChildrenPresentPositionAndSize();
};


TOptional<SRect> RWidget::GetPaintArea()
{
    assert(Parent&& "root widget  must overide this function"); 
    auto ParentArea=Parent->GetSubWidgetPaintArea();
    if(!ParentArea.HasValue())
    {
        return ParentArea;
    }
    return ParentArea.GetValue().Intersect(SRect(PresentAbsPosition,PresentSize));
}

TOptional<SRect> RWidget::GetSubWidgetPaintArea()
{
    assert(Parent);

    TOptional<SRect> ParentArea=Parent->GetSubWidgetPaintArea();
    if(!ParentArea.HasValue() || !bClipSubWidgets.Get() )
    {
        return ParentArea;
    }

    return ParentArea.GetValue().Intersect(SRect(PresentAbsPosition,PresentSize));

}

SVec2 RWidget::ToLocalPosition(SVec2 InPos)
{
    if(!Parent)
    {
        return InPos;
    }
    return (InPos - Parent->PresentAbsPosition)/ this->GetAccumulatedScale();//+SVec2(X.Get(),Y.Get());
}

RApplication * RWidget::GetApplication()
{
    return Parent->GetApplication();
}

float RWidget::CalculateChildrenBoundingBoxWidth()
{
    if(SubWidgets.Empty())
    {
        return 0;
    }

    float MaxX=std::numeric_limits<float>::lowest();
    float MinX=std::numeric_limits<float>::max();
    for(auto& Child:SubWidgets)
    {
        float ChildLeft=Child->PresentAbsPosition.X;
        float ChildRight=Child->PresentSize.X+Child->PresentAbsPosition.X;

        // in case widget is flipped 
        if(ChildLeft>ChildRight)
        {
            float Temp=ChildRight;
            ChildRight=ChildLeft;
            ChildLeft=Temp;
        }

       MaxX=CMathBase::Max(MaxX,ChildRight);
       MinX=CMathBase::Min(MinX,ChildLeft);
    }

    return MaxX-MinX;
}

float RWidget::CalculateChildrenBoundingBoxHeight()
{
    if(SubWidgets.Empty())
    {
        return 0;
    }

    float MaxY=std::numeric_limits<float>::lowest();
    float MinY=std::numeric_limits<float>::max();
    for(auto& Child:SubWidgets)
    {
        float ChildTop=Child->PresentAbsPosition.Y;
        float ChildBottom=Child->PresentSize.Y+Child->PresentAbsPosition.Y;

        // in case widget is flipped 
        if(ChildTop>ChildBottom)
        {
            float Temp=ChildBottom;
            ChildBottom=ChildTop;
            ChildTop=Temp;
        }

       MaxY=CMathBase::Max(MaxY,ChildBottom);
       MinY=CMathBase::Min(MinY,ChildTop);
    }

    return MaxY-MinY;    

}


RWindow* RWidget::GetWindow()
{
    if(!Tree)
    {
        assert(false && "can't get window from a unregisterd widget");
        return nullptr;
    }
    return Tree->GetWindow();

}

bool RWidget::IsMouseIn(const SIntPoint& MousePosition)
{
    if(!IsRegistered())
    {
        return false;
    }

    if (MousePosition.X >PresentAbsPosition.X 
    && MousePosition.X <=(PresentAbsPosition.X +PresentSize.X)
    && MousePosition.Y >PresentAbsPosition.Y 
    && MousePosition.Y <=(PresentAbsPosition.Y +PresentSize.Y)
    )
    {
        auto PaintArea=GetPaintArea();
        if(PaintArea.HasValue())
        {
            return PaintArea.GetValue().IsPointIn(SVec2(MousePosition.X,MousePosition.Y));
        }
    }

    return false;

}

bool RWidget::IsCurrentMouseIn()
{
    return IsMouseIn(GetWindow()->GetMousePositionInContent().ToVec2());
}

SVec2 RWidget::GetMousePositionInWidget()
{
    return GetWindow()->GetMousePositionInContent().ToVec2()-PresentAbsPosition;
}

SRect RWidget::GetRectInScreenSpace()
{
    return SRect(
        GetWindow()->GetWindowContentPosition().ToVec2()
        +PresentAbsPosition
        ,PresentSize
    );
}
